﻿using UnityEngine;
using System.Collections;

public class FX_AreaMoveOfObject : MonoBehaviour
{
	public class MyBezier
	{
		private Vector3 _p0;
		private Vector3 _p1;
		private Vector3 _p2;
		private Vector3 _p3;

		float _ti = 0f;

		private Vector3 _b0 = Vector3.zero;
		private Vector3 _b1 = Vector3.zero;
		private Vector3 _b2 = Vector3.zero;
		private Vector3 _b3 = Vector3.zero;

		private Vector3 _a = Vector3.zero;
		private Vector3 _b = Vector3.zero;
		private Vector3 _c = Vector3.zero;

		public MyBezier( Vector3 v0, Vector3 v1, Vector3 v2, Vector3 v3 )
		{
			_p0 = v0;
			_p1 = v1;
			_p2 = v2;
			_p3 = v3;
		}

		public Vector3 GetPointAtTime( float t )
		{
			t = t < 0f ? 0f : t > 1f ? 1f : t;
			_CheckConstant();
			var t2 = t * t;
			var t3 = t * t * t;
			var x = _a.x * t3 + _b.x * t2 + _c.x * t + _p0.x;
			var y = _a.y * t3 + _b.y * t2 + _c.y * t + _p0.y;
			var z = _a.z * t3 + _b.z * t2 + _c.z * t + _p0.z;
			return new Vector3( x, y, z );
		}


		public float CalcLength()
		{
			var len = 0f;
			for( int i = 0; i < 100; i++ )
				len += Vector3.Distance( GetPointAtTime( i * .01f ), GetPointAtTime( ( i + 1 ) * .01f ) );
			return len;
		}


		private void _SetConstant()
		{
			_c.x = 3 * ( ( _p0.x + _p1.x ) - _p0.x );
			_b.x = 3 * ( ( _p3.x + _p2.x ) - ( _p0.x + _p1.x ) ) - _c.x;
			_a.x = _p3.x - _p0.x - _c.x - _b.x;

			_c.y = 3 * ( ( _p0.y + _p1.y ) - _p0.y );
			_b.y = 3 * ( ( _p3.y + _p2.y ) - ( _p0.y + _p1.y ) ) - _c.y;
			_a.y = _p3.y - _p0.y - _c.y - _b.y;

			_c.z = 3 * ( ( _p0.z + _p1.z ) - _p0.z );
			_b.z = 3 * ( ( _p3.z + _p2.z ) - ( _p0.z + _p1.z ) ) - _c.z;
			_a.z = _p3.z - _p0.z - _c.z - _b.z;

		}

		private void _CheckConstant()
		{
			if( _p0 == _b0 && _p1 == _b1 && _p2 == _b2 && _p3 == _b3 )
				return;
			_SetConstant();
			_b0 = _p0;
			_b1 = _p1;
			_b2 = _p2;
			_b3 = _p3;
		}
	}
	
	public Vector3 Area = Vector3.one;
	public float Speed = 1f;
	public float Degree = 1f;

	private Vector3 _origin_position = Vector3.zero;
	private MyBezier _my_bezier;
	private float _cur_time = float.MaxValue;
	private float _max_time;

	private Vector3 _old_position = Vector3.zero;

	void Start()
	{
		_origin_position = transform.localPosition;
	}

	void Update()
	{
		Degree = Mathf.Clamp( Degree, 0.1f, 1f );

		if( _cur_time >= _max_time )
		{
			_cur_time = 0f;

			if( _old_position.Equals( Vector3.zero ) )
				_old_position = new Vector3( _origin_position.x + Area.x * _GetBeautifulRandomValue(), _origin_position.y + Area.y * _GetBeautifulRandomValue(), _origin_position.z + Area.z * _GetBeautifulRandomValue() );
			var end_position = new Vector3( _origin_position.x + Area.x * _GetBeautifulRandomValue(), _origin_position.y + Area.y * _GetBeautifulRandomValue(), _origin_position.z + Area.z * _GetBeautifulRandomValue() );
			var start_tangent = Vector3.up;
			var end_tangent = start_tangent.Equals( Vector3.up ) ? Vector3.down : Vector3.up;
			_my_bezier = new MyBezier( _old_position, start_tangent, end_tangent, end_position );
			_max_time = _my_bezier.CalcLength();
			_old_position = end_position;
		}

		transform.localPosition = _my_bezier.GetPointAtTime( _cur_time / _max_time );

		_cur_time += Time.deltaTime * Speed;
	}


	private float _GetBeautifulRandomValue()
	{
		return ( 1 - ( Random.value * Degree ) ) * ( Random.value <= 0.5f ? -1 : 1 );
	}
}
